package anonymouschat.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.LinkedList;

import anonymouschat.client.Client;
import anonymouschat.service.ServerEntry;

/**
 * Create an object that reads in all of the authorized public server identities
 * (i.e. the ones that were placed in the Constants.SERVER_FOLDER folder
 * 
 */
public class ListOfServers {

	public ArrayList<ServerEntry> servers = new ArrayList<ServerEntry>();

	FileInputStream fin;

	Client client = null;

	/**
	 * Read all the public identities available
	 */
	public ListOfServers() {
		Print.info("Creating a list of authorized servers. . .");
		File dir = new File(Constants.SERVER_FOLDER);
		String[] children = dir.list();
		if (children == null) {
			Print.error("No list of public servers to connect to");
			System.exit(1);
			// Either dir does not exist or is not a directory
		} else {
			for (int i = 0; i < children.length; i++) {
				// Get filename of file or directory
				String filename = Constants.SERVER_FOLDER + "/" + children[i];
				if (!filename.toLowerCase().endsWith(".dat")
						|| filename.toLowerCase().contains("private")
						|| filename.toLowerCase().contains("salt_")
						|| filename.toLowerCase().contains(".svn")) {
					continue;
				}

				ServerEntry ident = null;
				try {
					Print.debug("Reading object from " + filename);
					fin = new FileInputStream(filename);
					ObjectInputStream ois = new ObjectInputStream(fin);
					ident = (ServerEntry) ois.readObject();
					servers.add(ident);
					Print.debug("Added " + ident.serverName + " at "
							+ ident.serverIP + "/" + ident.serverPort
							+ " to list of known servers.");
					ois.close();
				} catch (FileNotFoundException e) {
					Print.error(
							"Could not load public server identity file for "
									+ filename, e);
				} catch (IOException e) {
					Print.error(
							"Unable to read serialized public server identity file for "
									+ filename, e);
				} catch (ClassNotFoundException e) {
					Print.error(
							"Error occured when casting read in serialized public server identity object to serverEntry for "
									+ filename, e, null);
				}
			}
		}
	}

	public ListOfServers(Client c) {
		this();
		client = c;
	}

	/**
	 * 
	 * @return a ServerEntry chosen at random, and not returned previously
	 * @throws Exception
	 */
	public ServerEntry getRandomServer(LinkedList<ServerEntry> chain)
			throws Exception {
		if (client == null) {
			throw new Exception(
					"Unable to establish anonymous route with out setting ListOfServers.client");
		}
		ServerEntry se;
		if (servers.size() == 0)
			throw new Exception(
					"The directory '"
							+ Constants.SERVER_FOLDER
							+ "' which holds information about how to connect to servers is empty, public server identities are [servername]Identity.dat files generated when a server is first run");
		if (chain.size() >= servers.size())
			throw new Exception(
					"Your number of server hops requested for anonymous routing is larger than the number of available servers, please reduce it to at most "
							+ servers.size());
		do {
			se = servers.get(Constants.secureRandom.nextInt(servers.size()));
		} while (chain.contains(se));
		return se;

	}

	public ServerEntry getByName(String name) {
		for (int i = 0; i < servers.size(); i++) {
			if (servers.get(i).serverName.equalsIgnoreCase(name))
				return servers.get(i);
		}
		return null;
	}
}
